<script setup lang="ts">
import { Slicer } from "@/models/reactiveComponent";
import { computed, ref, watch, inject } from "vue";
import * as injectKeys from "@/services/injectKeys";
import { watchOnce } from "@vueuse/core";

const props = defineProps<{ model: Slicer }>();
const model = props.model;

if ("multiple" in model.props) {
  model.multiple = model.props.multiple;
}

const dbServices = inject(injectKeys.dbKey)!;
const reactdataServices = inject(injectKeys.reactdataServicesKey)!;

const filterUtils = reactdataServices.getFilterUtils(model);

const appEventService = inject(injectKeys.appEventServiceKey)!;

appEventService.onResetFilters(() => {
  if (model.multiple) {
    selecteds.value = [];
  } else {
    selecteds.value = null;
  }
});

const data = filterUtils.getData();

let sqlPropName = null as unknown as string;

const options = computed(() => {
  if (data.value.rows.length > 0) {
    const rows = data.value.rows;

    if (!sqlPropName) {
      sqlPropName = data.value.fields[0];
    }

    return rows.map((r) => {
      // null or undefined
      const noValue = r[sqlPropName] === undefined || r[sqlPropName] === null;

      return {
        label: noValue ? "(空白)" : r[sqlPropName]!.toString(),
        value: noValue ? "(空白)" : r[sqlPropName]!,
      };
    });
  }

  return [];
});

const optionsInitCount = options.value.length;

const selecteds = ref<any[] | any>();

if (model.defaultSelected) {
  if (optionsInitCount > 0) {
    let value = options.value[0].value as any;

    if (model.multiple) {
      value = [value];
    }

    selecteds.value = value;
  }
}

watch(
  selecteds,
  (values) => {
    if (!Array.isArray(values)) {
      if (typeof values === "string" && values) {
        values = [values];
      } else {
        values = [];
      }
    }

    values = values.map((v: any) => {
      if (typeof v === "string" && v === "(空白)") {
        return null;
      }

      return v;
    });

    if (values.length === 0) {
      filterUtils.removeFilter();
    } else {
      const { hasNull, values: valuesWithoutNull } =
        dbServices.extractNullInValues(values);
      const sql = dbServices.valuesArray2sqlArray(valuesWithoutNull).join(",");

      filterUtils.addFilterWithExprFn((field) => {
        const expr = `${field} in (${sql})`;
        if (hasNull) {
          return `${expr} or ${field} is null`;
        }

        return expr;
      });
    }
  },
  { immediate: true }
);

const useV2 = optionsInitCount > 50;

let hiddenTitle = model.hiddenTitle ?? false;
</script>

<template>
  <div class="slicer-box">
    <label v-if="!hiddenTitle" class="title">{{ props.model.title }}</label>

    <el-select
      v-if="!useV2"
      :multiple="props.model.multiple"
      filterable
      clearable
      collapse-tags
      collapse-tags-tooltip
      v-model="selecteds"
      class="m-2"
      placeholder="Select"
      v-bind="model.props"
    >
      <el-option
        v-for="item in options"
        :key="item.label"
        :label="item.label"
        :value="item.value"
      />
    </el-select>

    <el-select-v2
      v-else
      class="cp-select"
      :options="options"
      :multiple="props.model.multiple"
      filterable
      clearable
      collapse-tags
      collapse-tags-tooltip
      v-model="selecteds"
      placeholder="Select"
      v-bind="model.props"
    >
    </el-select-v2>
  </div>
</template>

<style scoped lang="less">
.slicer-box {
  margin-right: 0.8rem;

  .cp-select {
    min-width: 11rem;
  }

  .title {
    display: block;
    margin-bottom: 0.5rem;
  }
}
</style>
